package com.fingard.util;

import java.util.*;

/**
 * Created by dalt on 2017/11/28.
 */
public class BijectionHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {
    private BijectionHashMap<V, K> otherSide;

    private Map<K, V> map = new HashMap<K, V>();

    public BijectionHashMap() {
        otherSide = new BijectionHashMap<V, K>(this);
    }

    public BijectionHashMap<V, K> reverse() {
        return otherSide;
    }

    private BijectionHashMap(BijectionHashMap<V, K> otherSide) {
        this.otherSide = otherSide;
    }

    public boolean containKey(K key) {
        return map.containsKey(key);
    }

    public V get(Object key) {
        return map.get(key);
    }

    public V remove(Object key) {
        V value = map.remove(key);
        otherSide.remove0(value);
        return value;
    }

    private V remove0(K key) {
        if (key == null) {
            return null;
        }
        return map.remove(key);
    }

    public V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException();
        }

        V v = map.put(key, value);
        otherSide.remove0(value);
        otherSide.put0(value, key);
        return v;
    }

    public V getOrDefault(Object key, V defaultVal) {
        V v = map.get(key);
        return v == null ? defaultVal : v;
    }

    public V getNotNull(K key) {
        V v = map.get(key);
        if (v == null) {
            throw new NullPointerException("未匹配关键字[" + key + "]");
        }
        return v;
    }

    private void put0(K key, V value) {
        map.put(key, value);
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    @SuppressWarnings("unchecked")
	@Override
    public boolean containsValue(Object value) {
        return reverse().containKey((V) value);
    }

    @Override
    public Set<K> keySet() {
        return map.keySet();
    }

    @Override
    public Collection<V> values() {
        return map.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        return map.entrySet();
    }
}
